/**
The MIT License (MIT)

Copyright (c) 2014 singwhatiwanna
https://github.com/singwhatiwanna
http://blog.csdn.net/singwhatiwanna

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package com.lst.projectlib.component.ExpandListView;

import java.util.NoSuchElementException;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;


public class StickyLayout extends LinearLayout {

    public interface OnGiveUpTouchEventListener {
        public boolean giveUpTouchEvent(MotionEvent event);
    }

    private View mHeader;
    private View mContent;
    private OnGiveUpTouchEventListener mGiveUpTouchEventListener;

    private int mHeaderHeight;
    private int mOriginalHeaderTop;
    private int mOriginalContentTop;
    private int mHeaderTop;

    private int mStatus = STATUS_EXPANDED;
    public static final int STATUS_EXPANDED = 1;
    public static final int STATUS_COLLAPSED = 2;

    private int mTouchSlop;

    private int mLastX = 0;
    private int mLastY = 0;

    private int mLastXIntercept = 0;
    private int mLastYIntercept = 0;

    private boolean mInitDataSucceed = false;
    
    public StickyLayout(Context context) {
        super(context);
    }

    public StickyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public StickyLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if (hasWindowFocus && (mHeader == null || mContent == null)) {
            initData();
        }
    }

    private void initData() {
        int headerId= getResources().getIdentifier("sticky_header", "id", getContext().getPackageName());
        int contentId = getResources().getIdentifier("sticky_content", "id", getContext().getPackageName());
        if (headerId != 0 && contentId != 0) {
            mHeader = findViewById(headerId);
            mContent = findViewById(contentId);
            mHeaderHeight = mHeader.getMeasuredHeight();
            mOriginalHeaderTop = mHeader.getTop();
            mOriginalContentTop = mContent.getTop();
            mTouchSlop = 0;
//            mTouchSlop = ViewConfiguration.get(getContent()).getScaledTouchSlop();
            if (mHeaderHeight > 0) {
            	mInitDataSucceed = true;
            }
        } else {
            throw new NoSuchElementException("Did your view with id \"sticky_header\" or \"sticky_content\" exists?");
        }
    }

    public void setOnGiveUpTouchEventListener(OnGiveUpTouchEventListener l) {
        mGiveUpTouchEventListener = l;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
    	int intercepted = 0;
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            mLastXIntercept = x;
            mLastYIntercept = y;
            mLastX = x;
            mLastY = y;
            intercepted = 0;
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastXIntercept;
            int deltaY = y - mLastYIntercept;
            
            if (Math.abs(deltaY) <= Math.abs(deltaX)) {
                intercepted = 0;
            } else if (mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop && (mContent.getTop() + deltaY > mOriginalContentTop - mHeaderHeight || mHeader.getTop() + deltaY > -mHeaderHeight)) {
                intercepted = 1;
            } else if (mStatus == STATUS_COLLAPSED && deltaY >= mTouchSlop && (mContent.getTop() + deltaY < mOriginalContentTop || mHeader.getTop() + deltaY < mOriginalHeaderTop)) {
				if (mGiveUpTouchEventListener != null) {
					if (mGiveUpTouchEventListener.giveUpTouchEvent(event)) {
						intercepted = 1;
					}
				}
            } else {
            	intercepted = 0;
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            intercepted = 0;
            mLastXIntercept = mLastYIntercept = 0;
            break;
        }
        default:
            break;
        }

        onTouchChild(mContent, intercepted);
        return false;
//        return intercepted != 0;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            float deltaY = y - mLastY;
            
			// 跟随手指滑动
			scrollByDeltaY(deltaY);
            break;
        }
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
        {
        	int destTop = 0;
        	// 如果当前位置已经超过头部View的高度的一半的时候，
        	// 则自动平滑的滚动到隐藏头部view的位置
            if (Math.abs(mHeaderTop) > mHeaderHeight * 0.5) {
            	destTop = -mHeaderHeight;
                mStatus = STATUS_COLLAPSED;
            } else {
            	// 否则则滚动到全部显示的位置
            	destTop = mOriginalHeaderTop;
                mStatus = STATUS_EXPANDED;
            }
            this.smoothScrollByDeltaY(destTop, 500);
            break;
        }
        default:
            break;
        }
        mLastX = x;
        mLastY = y;
        
        return true;
//        return onTouchChild(mContent, event);
    }
    
    /**
     * 滚动一定的距离
     */
    private void scrollByDeltaY (float deltaY) {
        if (!mInitDataSucceed) {
            initData();
        }
        
    	// 即将滑动到的位置
        int headerTop, contentTop, headerBottom, contentBottom;
        
    	// 如果已经滑动到完全隐藏头部view的位置的时候，就不再滑动(向上滑动)
    	if (mContent.getTop() + deltaY <= mOriginalContentTop - mHeaderHeight || mHeader.getTop() + deltaY <= -mHeaderHeight) {
    		headerTop = mOriginalHeaderTop - mHeaderHeight;
    		contentTop = mOriginalContentTop - mHeaderHeight;
    		headerBottom = mOriginalHeaderTop;
    		contentBottom = (int) (mContent.getBottom());
    		mStatus = STATUS_COLLAPSED;
    		
    	} else if (mContent.getTop() + deltaY >= mOriginalContentTop || mHeader.getTop() + deltaY >= mOriginalHeaderTop) {
    		// 如果已经滑动到完全显示头部view的位置的时候，就不再滑动(向下滑动)
    		headerTop = mOriginalHeaderTop;
    		contentTop = mOriginalContentTop;
    		headerBottom = mOriginalHeaderTop + mHeaderHeight;
    		contentBottom = (int) (mContent.getBottom());
    		mStatus = STATUS_EXPANDED;
    		
    	} else {
    		headerTop = (int) (mHeader.getTop() + deltaY);
    		contentTop = (int) (mContent.getTop() + deltaY);
    		headerBottom = (int) (mHeader.getBottom() + deltaY);
    		contentBottom = (int) (mContent.getBottom());
    		mStatus = STATUS_EXPANDED;
    		
    	}
    	// 存储下来当前滚动到的top
    	mHeaderTop = headerTop;
    	
    	// 更改头部View的位置
		mHeader.layout(mHeader.getLeft(), headerTop,
				mHeader.getRight(), headerBottom);
		
		// 更改内容View的位置
		mContent.layout(mContent.getLeft(), contentTop,
				mContent.getRight(), contentBottom);
    }
    
    private void onTouchChild(View view, int intercept) {
    	if (view instanceof ViewGroup) {
    		ViewGroup parent = (ViewGroup)view;
    		
			if (view instanceof ListView) {
				view.setTag(intercept);
			} else {
				for (int i = 0; i < parent.getChildCount(); i++) {
					View childView = parent.getChildAt(i);
					onTouchChild(childView, intercept);
				}
			}
		}
    }
    
    private void layoutChild(View view, int widthMeasureSpec, int heightMeasureSpec) {
    	if (view instanceof ViewGroup) {
    		ViewGroup parent = (ViewGroup)view;
    		parent.setClipChildren(false);
    		
			if (view instanceof ListView) {
				measureChild(view, widthMeasureSpec, heightMeasureSpec);
			} else {
				for (int i = 0; i < parent.getChildCount(); i++) {
					View childView = parent.getChildAt(i);
					layoutChild(childView, widthMeasureSpec, heightMeasureSpec);
				}
			}
		}
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    	super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		// 让内容View中的子view充满内容View
    	layoutChild(mContent, widthMeasureSpec, heightMeasureSpec);
    	
    }
    
    /**
     * 平滑的滚动到相应位置
     * @param destTop
     * @param duration
     */
    private void smoothScrollByDeltaY (final int destTop, long duration) {
    	// 即将需要滑动的距离
    	int position = destTop - mHeaderTop;
    	// 计算需要的帧数
    	final int frameCount = (int) (duration / 1000f * 30) + 1;
    	// 每帧需要滚动的单位距离
        final float partation = position / (float) frameCount;
    	// 逐帧播放
    	new Thread("Thread#smoothScrollByDeltaY") {
            @Override
            public void run() {
                for (int i = 0; i < frameCount; i++) {
                    post(new Runnable() {
                        public void run() {
                        	if (mHeader != null) {
                        		// 如果是这种情况代表画面自动刷新成原样了，
                        		// 需要做处理给改回来
//                        		if ((mHeader.getTop() >= mOriginalHeaderTop && mStatus == STATUS_COLLAPSED) ||
//                        				(mHeader.getTop() <= -mHeaderHeight && mStatus == STATUS_EXPANDED)) {
//                        			scrollByDeltaY(destTop);
//                        			return;
//                        		}
                        	}
                        	scrollByDeltaY(partation);
                        }
                    });
                    try {
                        sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };

        }.start();
    }
    
    @Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);

		int destTop;
		if (mStatus == STATUS_COLLAPSED) {
			destTop = -mHeaderHeight;
		} else {
			destTop = mOriginalHeaderTop;
		}
		// 如果是这种情况代表画面自动刷新成原样了，
		// 需要做处理给改回来
		if (mHeader != null) {
			if ((mHeader.getTop() >= mOriginalHeaderTop && mStatus == STATUS_COLLAPSED)
					|| (mHeader.getTop() <= -mHeaderHeight && mStatus == STATUS_EXPANDED)) {
				scrollByDeltaY(destTop);
			}
		}
	}

//    public void recoverHeaderHeight() {
//    	this.smoothScrollByDeltaY(0, 0);
//    }
}